/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.servlets;

import com.codemagi.util.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.JDOManager;
import org.exolab.castor.mapping.Mapping;

/**
 * BaseFilter is a supercalss for all filters which need access to the JDO database.
 *
 *  @version 1.0
 *  @author August Detlefsen for CodeMagi, Inc.
 */
public abstract class BaseFilter implements Filter {

    static Logger log = Logger.getLogger("com.codemagi.servlets.BaseFilter");

    //constants
    protected static final String WEB_INF_DIR = "WEB-INF/";
    protected static final String ETC_DIR     = "etc/";
    protected static final String ICONS_DIR   = "icons/";

    protected static final String MAPPING_FILE  = "mapping.xml";
    protected static final String DATABASE_FILE = "database.xml";

    //members
    //location of this servlet
    protected String location = "";

    //application context
    protected ServletContext application;

    //JDO instance
    protected Mapping mapping;
    protected JDOManager jdo;


    /**
     * Initializes the filter when it is loaded by the
     * servlet engine.
     *
     * @param config the configuration as <code>ServletConfig</code>
     *
     * @throws ServletException if initialization fails.
     */
    public void init(FilterConfig config)
        throws ServletException {

        log.info(this.getClass().getName() + " - init");

	//get a handle on the application context
	application = config.getServletContext();

        //get this servlet location
        location = application.getRealPath("/");
	log.debug("location: " + location);

        //build JDO, get DB connection
        try {
	    //read config params from context
	    String mappingFile = config.getInitParameter("mapping.xml");
	    log.debug("mapping file from param: " + mappingFile);
	    if (mappingFile == null) mappingFile = MAPPING_FILE;
	    String mappingFileLocation = location + WEB_INF_DIR + ETC_DIR + mappingFile;
	    URL mappingUrl = application.getResource("/" + WEB_INF_DIR + ETC_DIR + mappingFile);
	    
	    log.debug("mapping URL: " + mappingUrl.toString());

	    String databaseFile = config.getInitParameter("database.xml");
	    log.debug("database file from param: " + databaseFile);
	    if (databaseFile == null) databaseFile = DATABASE_FILE;
	    String databaseFileLocation = location + WEB_INF_DIR + ETC_DIR + databaseFile;
	    URL databaseURL = application.getResource("/" + WEB_INF_DIR + ETC_DIR + databaseFile);
	    
	    String databaseName = config.getInitParameter("database.name");
	    log.debug("databaseName: " + databaseName);
	    if (databaseName == null) databaseName = "database";
	    
            mapping = new Mapping( BaseFilter.class.getClassLoader() );
            
            log.debug("about to load mapping");
            mapping.loadMapping( mappingUrl );
            log.debug(" ...done");

	    log.debug("about to load JDO config from: " + databaseFileLocation);
            jdo.loadConfiguration(databaseFileLocation);
            log.debug("about to create JDO instance: " + databaseName);
            jdo = JDOManager.createInstance(databaseName);
            log.debug(" ...done");
            log.debug("JDO: " + jdo);

        } catch (Exception e) {
            log.debug("", e);

            throw new ServletException(e);
        }

    }


    public void destroy() {
	//no-op
    }


    //JDO UTILITY METHODS ------------------------------------------------------------------------


    /**
     * Returns a JDO database instance
     */
    public Database getJDODatabase() 
        throws org.exolab.castor.jdo.DatabaseNotFoundException,
               org.exolab.castor.jdo.PersistenceException {
        return jdo.getDatabase();
    }


    /**
     * Closes a JDO database instance
     */
    public static void closeJDODatabase(Database db) {
	try {
	    log.debug("Closing JDO Database");

	    //rollback transaction                                                                                              
	    if (db != null && db.isActive()) {
		log.debug("   -Rollback");
		db.rollback();
	    }

	    if (db != null && !db.isClosed()) {
		log.debug("   -Close");
		db.close();
	    }

	    db = null;

	} catch (Exception fe) {
	    log.debug("", fe);
	}
    }


    //UTILITY METHODS ----------------------------------------------

    /**
     * Closes a Stream
     */
    public static void closeStream(Closeable s) {
	try {
	    if (s != null) s.close();
	    s = null;
	} catch (IOException ioe) {
	    log.debug("", ioe);
	}
    }


    /**
     * Returns the server name portion of the request URL. 
     * For example, if the request URL is: 
     * <BR><BR>
     * http://www.codemagi.com/servlet?param1=value1
     * <BR><BR>  
     * Then this method will return: 
     * <BR><BR>  
     * http://www.codemagi.com
     */
    public static String getServerName(HttpServletRequest request) {
	StringBuffer url  = request.getRequestURL();
	return url.substring(0, url.indexOf("/", url.indexOf("//") +2));
    }


    /**
     * Logs the request attributes. The attribute "content" is skipped due to its size.
     */
    public void logRequestAttributes(HttpServletRequest request) {
	log.debug("REQUEST ATTRIBUTES: ");

	Enumeration e = request.getAttributeNames();
	while (e.hasMoreElements()) {
	    String name  = (String)e.nextElement();
	    Object value = request.getAttribute(name);

	    if ( !("content".equals(name) || "password".equals(name)) ) log.debug("    - " + name + " = " + value);
	}
    }

    
    /**
     * Logs the request parameters. 
     */
    public void logRequestParameters(HttpServletRequest request) {
	log.debug("REQUEST PARAMETERS: ");

	Enumeration e = request.getParameterNames();
	while (e.hasMoreElements()) {
	    String name  = (String)e.nextElement();
	    Object value = request.getParameter(name);

	    if ( !("content".equals(name) || "password".equals(name) || 
		   "pass1".equals(name) || "pass2".equals(name)) ) log.debug("    - " + name + " = " + value);
	}
    }


    /**
     * Logs the request headers. 
     */
    public void logRequestHeaders(HttpServletRequest request) {
	log.debug("REQUEST HEADERS: ");

	Enumeration e = request.getHeaderNames();
	while (e.hasMoreElements()) {
	    String name  = (String)e.nextElement();
	    Object value = request.getHeader(name);

	    if ( !("content".equals(name) || "password".equals(name)) ) log.debug("    - " + name + " = " + value);
	}
    }

    
    /**
     * Logs the session attributes. The attribute "content" is skipped due to its size.
     */
    public void logSessionAttributes(HttpServletRequest request) {
	log.debug("SESSION ATTRIBUTES: ");

	HttpSession session = request.getSession();

	Enumeration e = session.getAttributeNames();
	while (e.hasMoreElements()) {
	    String name  = (String)e.nextElement();
	    Object value = session.getAttribute(name);

	    if (!"content".equals(name)) log.debug("    - " + name + " = " + value);
	}
    }

   
    /**                                                                                                                
     * Attempts to load an init parameter from the filter config. If no value is found in                              
     * the filter config, it will try the application. If nothing is found in the application                              
     * context, the default value is returned.                  
     * 
     * This implementation tries to parse the init parameter as a boolean. If the input cannot be 
     * parsed as a boolean, the default value will be returned.
     */
    protected Boolean loadInitParameter(FilterConfig config, String paramName, Boolean defaultValue) {

        log.debug("Loading init parameter: " + paramName);

	if (config == null) return defaultValue;

        String param = config.getInitParameter(paramName);
	log.debug("    value from servlet config: " + param);

        if (Utils.isEmpty(param)) {
            param = config.getServletContext().getInitParameter(paramName);
            log.debug("    value from context config: " + param);
        }

	if ("true".equalsIgnoreCase(param)) {
	    return true;

	} else if ("false".equalsIgnoreCase(param)) {
	    return false;

	}	
	
        return defaultValue;
    }

    
}
